#define _USE_MATH_DEFINES
#include "math.h"
#include <iostream>
#include "GLC_SolveRoot.h"

double f(double x)
{
    return sin(x) - 0.5;
}

double df(double x)
{
    return cos(x);
}

double mini(double (*f)(double), double x0, double x1, double x3, double eps = 1e-8, int maxiter = 1000)
{
    double f0 = f(x0), f1 = f(x1), f3 = f(x3), x2 = 0, f2;
    double lambda = 0.618;
    int i = 0;
    double mini;

    while (abs(x3 - x0) > eps * (abs(x1) + abs(x2)) && i < maxiter)
    {
        if ((x3 - x1) > (x1 - x0))
        {
            x2 = lambda * x1 + (1 - lambda) * x3;
            f1 = f(x1);
            f2 = f(x2);
            if (f2 > f1)
            {
                x3 = x2;
            }
            else
            {
                x0 = x1;
                x1 = x2;
            }
        }
        else
        {
            x2 = (1 - lambda) * x0 + lambda * x1;
            f2 = f(x2);
            f1 = f(x1);
            if (f2 > f1)
            {
                x0 = x2;
            }
            else
            {
                x3 = x1;
                x1 = x2;
            }
        }
        i++;
    }
    if (f(x1) > f(x2))
    {
        mini = x2;
    }
    else
    {
        mini = x1;
    }

    std::cout << "total iters are  " << i << std::endl;
    std::cout << "find mini at " << mini << std::endl;
    std::cout << "the fmin is " << f(mini) << std::endl;
    return mini;
}

int main(int argc, char const *argv[])
{
    using namespace GLC;
    double pi = M_PI;
    SolveRoot<double> sr(f);
    sr.Bisection(0, pi / 2.0);
    sr.Bisection(pi / 2.0, pi);
    sr.Newton(0.1, df);
    sr.Newton(2.1, df);
    sr.Newton(pi / 2.0, df);
    sr.Secant(0, 0.1);
    sr.Secant(2.0, 2.1);
    sr.Secant(pi / 2, pi / 2 + 0.1);

    mini(f, pi / 2, pi / 2 + 0.1, 3 * pi / 2 + 0.1);
    return 0;
}
